home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / nfsmount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  11.3 KB  |  478 lines

  1. /*
  2.  * nfsmount.c -- Linux NFS mount
  3.  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  16.  * numbers to be specified on the command line.
  17.  */
  18.  
  19. /*
  20.  * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <rpc/rpc.h>
  25. #include <rpc/pmap_prot.h>
  26. #include <rpc/pmap_clnt.h>
  27. #include <sys/socket.h>
  28. #include <sys/time.h>
  29. #include <string.h>
  30. #include <netdb.h>
  31. #include <arpa/inet.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <unistd.h>
  35.  
  36. #include "log.h"
  37. #include "mount.h"
  38.  
  39. #include <linux/fs.h>
  40. #include <linux/nfs.h>
  41. #include <linux/nfs_mount.h>
  42.  
  43. #ifndef __alpha__
  44. static char *strndup (char *str, int n) {
  45.   char *ret;
  46.   ret = malloc (n+1);
  47.   if (ret == NULL) {
  48.     perror ("malloc");
  49.     return (NULL);
  50.   }
  51.   strncpy (ret, str, n);
  52.   return (ret);
  53. }
  54. #endif
  55.  
  56. static char *nfs_strerror(int stat);
  57.  
  58. int nfsmount(const char *spec, const char *node, int *flags,
  59.          char **extra_opts, char **mount_opts)
  60. {
  61.     char hostdir[1024];
  62.     CLIENT *mclient;
  63.     char *hostname;
  64.     char *dirname;
  65.     char *old_opts;
  66.     char *mounthost=NULL;
  67.     char new_opts[1024];
  68.     fhandle root_fhandle;
  69.     struct timeval total_timeout;
  70.     enum clnt_stat clnt_stat;
  71.     static struct nfs_mount_data data;
  72.     char *opt, *opteq;
  73.     int val;
  74.     struct hostent *hp;
  75.     struct sockaddr_in server_addr;
  76.     struct sockaddr_in mount_server_addr;
  77.     int msock, fsock;
  78.     struct timeval pertry_timeout;
  79.     struct fhstatus status;
  80.     char *s;
  81.     int port;
  82.     int mountport;
  83.     int bg;
  84.     int soft;
  85.     int intr;
  86.     int posix;
  87.     int nocto;
  88.     int noac;
  89.     int retry;
  90.     int tcp;
  91.     int mountprog;
  92.     int mountvers;
  93.     int nfsprog;
  94.     int nfsvers;
  95.  
  96.     msock = fsock = -1;
  97.     mclient = NULL;
  98.     strcpy(hostdir, spec);
  99.     if ((s = (strchr(hostdir, ':')))) {
  100.         hostname = hostdir;
  101.         dirname = s + 1;
  102.         *s = '\0';
  103.     }
  104.     else {
  105.         logMessage("mount: "
  106.             "directory to mount not in host:dir format");
  107.         goto fail;
  108.     }
  109.  
  110.     if (hostname[0] >= '0' && hostname[0] <= '9') {
  111.         server_addr.sin_family = AF_INET;
  112.         server_addr.sin_addr.s_addr = inet_addr(hostname);
  113.     }
  114.     else if ((hp = gethostbyname(hostname)) == NULL) {
  115.         logMessage("mount: can't get address for %s", hostname);
  116.         goto fail;
  117.     }
  118.     else {
  119.         server_addr.sin_family = AF_INET;
  120.         memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
  121.     }
  122.  
  123.     memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
  124.  
  125.     /* add IP address to mtab options for use when unmounting */
  126.  
  127.     old_opts = *extra_opts;
  128.     if (!old_opts)
  129.         old_opts = "";
  130.     sprintf(new_opts, "%s%saddr=%s",
  131.         old_opts, *old_opts ? "," : "",
  132.         inet_ntoa(server_addr.sin_addr));
  133.     *extra_opts = strdup(new_opts);
  134.  
  135.     /* set default options */
  136.  
  137.     data.rsize    = 0; /* let kernel decide */
  138.     data.wsize    = 0; /* let kernel decide */
  139.     data.timeo    = 7;
  140.     data.retrans    = 3;
  141.     data.acregmin    = 3;
  142.     data.acregmax    = 60;
  143.     data.acdirmin    = 30;
  144.     data.acdirmax    = 60;
  145. #if NFS_MOUNT_VERSION >= 2
  146.     data.namlen    = NAME_MAX;
  147. #endif
  148.  
  149.     bg = 0;
  150.     soft = 0;
  151.     intr = 0;
  152.     posix = 0;
  153.     nocto = 0;
  154.     noac = 0;
  155.     retry = 10000;
  156.     tcp = 0;
  157.  
  158.     mountprog = MOUNTPROG;
  159.     mountvers = MOUNTVERS;
  160.     port = 0;
  161.     mountport = 0;
  162.     nfsprog = NFS_PROGRAM;
  163.     nfsvers = NFS_VERSION;
  164.  
  165.     /* parse options */
  166.  
  167.     for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
  168.         if ((opteq = strchr(opt, '='))) {
  169.             val = atoi(opteq + 1);    
  170.             *opteq = '\0';
  171.             if (!strcmp(opt, "rsize"))
  172.                 data.rsize = val;
  173.             else if (!strcmp(opt, "wsize"))
  174.                 data.wsize = val;
  175.             else if (!strcmp(opt, "timeo"))
  176.                 data.timeo = val;
  177.             else if (!strcmp(opt, "retrans"))
  178.                 data.retrans = val;
  179.             else if (!strcmp(opt, "acregmin"))
  180.                 data.acregmin = val;
  181.             else if (!strcmp(opt, "acregmax"))
  182.                 data.acregmax = val;
  183.             else if (!strcmp(opt, "acdirmin"))
  184.                 data.acdirmin = val;
  185.             else if (!strcmp(opt, "acdirmax"))
  186.                 data.acdirmax = val;
  187.             else if (!strcmp(opt, "actimeo")) {
  188.                 data.acregmin = val;
  189.                 data.acregmax = val;
  190.                 data.acdirmin = val;
  191.                 data.acdirmax = val;
  192.             }
  193.             else if (!strcmp(opt, "retry"))
  194.                 retry = val;
  195.             else if (!strcmp(opt, "port"))
  196.                 port = val;
  197.             else if (!strcmp(opt, "mountport"))
  198.                     mountport = val;
  199.             else if (!strcmp(opt, "mounthost"))
  200.                     mounthost=strndup(opteq+1,
  201.                           strcspn(opteq+1," \t\n\r,"));
  202.             else if (!strcmp(opt, "mountprog"))
  203.                 mountprog = val;
  204.             else if (!strcmp(opt, "mountvers"))
  205.                 mountvers = val;
  206.             else if (!strcmp(opt, "nfsprog"))
  207.                 nfsprog = val;
  208.             else if (!strcmp(opt, "nfsvers"))
  209.                 nfsvers = val;
  210.             else if (!strcmp(opt, "namlen")) {
  211. #if NFS_MOUNT_VERSION >= 2
  212.                 data.namlen = val;
  213. #else
  214.                 logMessage("Warning: Option namlen is not supported.");
  215. #endif
  216.             }
  217.             else if (!strcmp(opt, "addr"))
  218.                 /* ignore */;
  219.             else {
  220.                 logMessage("unknown nfs mount parameter: "
  221.                        "%s=%d", opt, val);
  222.                 goto fail;
  223.             }
  224.         }
  225.         else {
  226.             val = 1;
  227.             if (!strncmp(opt, "no", 2)) {
  228.                 val = 0;
  229.                 opt += 2;
  230.             }
  231.             if (!strcmp(opt, "bg")) 
  232.                 bg = val;
  233.             else if (!strcmp(opt, "fg")) 
  234.                 bg = !val;
  235.             else if (!strcmp(opt, "soft"))
  236.                 soft = val;
  237.             else if (!strcmp(opt, "hard"))
  238.                 soft = !val;
  239.             else if (!strcmp(opt, "intr"))
  240.                 intr = val;
  241.             else if (!strcmp(opt, "posix"))
  242.                 posix = val;
  243.             else if (!strcmp(opt, "cto"))
  244.                 nocto = !val;
  245.             else if (!strcmp(opt, "ac"))
  246.                 noac = !val;
  247.             else if (!strcmp(opt, "tcp"))
  248.                 tcp = val;
  249.             else if (!strcmp(opt, "udp"))
  250.                 tcp = !val;
  251.             else {
  252.                 logMessage("unknown nfs mount option: "
  253.                        "%s%s", val ? "" : "no", opt);
  254.                 goto fail;
  255.             }
  256.         }
  257.     }
  258.     data.flags = (soft ? NFS_MOUNT_SOFT : 0)
  259.         | (intr ? NFS_MOUNT_INTR : 0)
  260.         | (posix ? NFS_MOUNT_POSIX : 0)
  261.         | (nocto ? NFS_MOUNT_NOCTO : 0)
  262.         | (noac ? NFS_MOUNT_NOAC : 0);
  263. #if NFS_MOUNT_VERSION >= 2
  264.     data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
  265. #endif
  266.  
  267. #ifdef NFS_MOUNT_DEBUG
  268.     logMessage("rsize = %d, wsize = %d, timeo = %d, retrans = %d",
  269.         data.rsize, data.wsize, data.timeo, data.retrans);
  270.     logMessage("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)",
  271.         data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
  272.     logMessage("port = %d, bg = %d, retry = %d, flags = %.8x",
  273.         port, bg, retry, data.flags);
  274.     logMessage("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d",
  275.         mountprog, mountvers, nfsprog, nfsvers);
  276.     logMessage("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d",
  277.         (data.flags & NFS_MOUNT_SOFT) != 0,
  278.         (data.flags & NFS_MOUNT_INTR) != 0,
  279.         (data.flags & NFS_MOUNT_POSIX) != 0,
  280.         (data.flags & NFS_MOUNT_NOCTO) != 0,
  281.         (data.flags & NFS_MOUNT_NOAC) != 0);
  282. #if NFS_MOUNT_VERSION >= 2
  283.     logMessage("tcp = %d",
  284.         (data.flags & NFS_MOUNT_TCP) != 0);
  285. #endif
  286. #if 0
  287.     goto fail;
  288. #endif
  289. #endif
  290.  
  291.     data.version = NFS_MOUNT_VERSION;
  292.     *mount_opts = (char *) &data;
  293.  
  294.     if (*flags & MS_REMOUNT)
  295.         return 0;
  296.  
  297.     /* create mount deamon client */
  298.     /* See if the nfs host = mount host. */
  299.     if (mounthost) {
  300.       if (mounthost[0] >= '0' && mounthost[0] <= '9') {
  301.         mount_server_addr.sin_family = AF_INET;
  302.         mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
  303.       }
  304.       else if ((hp = gethostbyname(mounthost)) == NULL) {
  305.         logMessage("mount: can't get address for %s", hostname);
  306.         goto fail;
  307.       }
  308.       else {
  309.         mount_server_addr.sin_family = AF_INET;
  310.         memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length);
  311.       }
  312.     }
  313.  
  314.     mount_server_addr.sin_port = htons(mountport);
  315.     msock = RPC_ANYSOCK;
  316.     if ((mclient = clnttcp_create(&mount_server_addr,
  317.         mountprog, mountvers, &msock, 0, 0)) == NULL) {
  318.         mount_server_addr.sin_port = htons(mountport);
  319.         msock = RPC_ANYSOCK;
  320.         pertry_timeout.tv_sec = 3;
  321.         pertry_timeout.tv_usec = 0;
  322.         if ((mclient = clntudp_create(&mount_server_addr,
  323.             mountprog, mountvers, pertry_timeout, &msock)) == NULL) {
  324.             clnt_pcreateerror("mount clntudp_create");
  325.             goto fail;
  326.         }
  327. #ifdef NFS_MOUNT_DEBUG
  328.         logMessage("using UDP for mount deamon");
  329. #endif
  330.     }
  331. #ifdef NFS_MOUNT_DEBUG
  332.     else
  333.         logMessage("using TCP for mount deamon");
  334. #endif
  335.     mclient->cl_auth = authunix_create_default();
  336.     total_timeout.tv_sec = 20;
  337.     total_timeout.tv_usec = 0;
  338.  
  339.     /* try to mount hostname:dirname */
  340.  
  341.     clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
  342.         xdr_dirpath, &dirname,
  343.         xdr_fhstatus, &status,
  344.         total_timeout);
  345.     if (clnt_stat != RPC_SUCCESS) {
  346.         clnt_perror(mclient, "rpc mount");
  347.         goto fail;
  348.     }
  349.     if (status.fhs_status != 0) {
  350.         logMessage("mount: %s:%s failed, reason given by server: %s",
  351.             hostname, dirname, nfs_strerror(status.fhs_status));
  352.         goto fail;
  353.     }
  354.     memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle,
  355.         sizeof (root_fhandle));
  356.  
  357.     /* create nfs socket for kernel */
  358.  
  359.     if (tcp) {
  360. #if NFS_MOUNT_VERSION >= 2
  361.         fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  362. #else
  363.         logMessage("NFS over TCP is not supported.");
  364.         goto fail;
  365. #endif
  366.     }
  367.     else
  368.         fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  369.     if (fsock < 0) {
  370.         perror("nfs socket");
  371.         goto fail;
  372.     }
  373.     if (bindresvport(fsock, 0) < 0) {
  374.         perror("nfs bindresvport");
  375.         goto fail;
  376.     }
  377.     if (port == 0) {
  378.         server_addr.sin_port = PMAPPORT;
  379.         port = pmap_getport(&server_addr, nfsprog, nfsvers,
  380.             tcp ? IPPROTO_TCP : IPPROTO_UDP);
  381.         if (port == 0)
  382.             port = NFS_PORT;
  383. #ifdef NFS_MOUNT_DEBUG
  384.         else
  385.             logMessage("used portmapper to find NFS port");
  386. #endif
  387.     }
  388. #ifdef NFS_MOUNT_DEBUG
  389.     logMessage("using port %d for nfs deamon", port);
  390. #endif
  391.     server_addr.sin_port = htons(port);
  392.     if (connect(fsock, (struct sockaddr *) &server_addr,
  393.         sizeof (server_addr)) < 0) {
  394.         perror("nfs connect");
  395.         goto fail;
  396.     }
  397.  
  398.     /* prepare data structure for kernel */
  399.  
  400.     data.fd = fsock;
  401.     memcpy((char *) &data.root, (char *) &root_fhandle,
  402.         sizeof (root_fhandle));
  403.     memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
  404.     strncpy(data.hostname, hostname, sizeof(data.hostname));
  405.  
  406.     /* clean up */
  407.  
  408.     auth_destroy(mclient->cl_auth);
  409.     clnt_destroy(mclient);
  410.     close(msock);
  411.     return 0;
  412.  
  413.     /* abort */
  414.  
  415. fail:
  416.     if (msock != -1) {
  417.         auth_destroy(mclient->cl_auth);
  418.         clnt_destroy(mclient);
  419.         close(msock);
  420.     }
  421.     if (fsock != -1)
  422.         close(fsock);
  423.     return 1;}
  424.     
  425.  
  426. /*
  427.  * We need to translate between nfs status return values and
  428.  * the local errno values which may not be the same.
  429.  */
  430.  
  431. #ifndef EDQUOT
  432. #define EDQUOT    ENOSPC
  433. #endif
  434.  
  435. static struct {
  436.     enum nfs_stat stat;
  437.     int errno;
  438. } nfs_errtbl[] = {
  439.     { NFS_OK,        0        },
  440.     { NFSERR_PERM,        EPERM        },
  441.     { NFSERR_NOENT,        ENOENT        },
  442.     { NFSERR_IO,        EIO        },
  443.     { NFSERR_NXIO,        ENXIO        },
  444.     { NFSERR_ACCES,        EACCES        },
  445.     { NFSERR_EXIST,        EEXIST        },
  446.     { NFSERR_NODEV,        ENODEV        },
  447.     { NFSERR_NOTDIR,    ENOTDIR        },
  448.     { NFSERR_ISDIR,        EISDIR        },
  449. #ifdef NFSERR_INVAL
  450.     { NFSERR_INVAL,        EINVAL        },    /* that Sun forgot */
  451. #endif
  452.     { NFSERR_FBIG,        EFBIG        },
  453.     { NFSERR_NOSPC,        ENOSPC        },
  454.     { NFSERR_ROFS,        EROFS        },
  455.     { NFSERR_NAMETOOLONG,    ENAMETOOLONG    },
  456.     { NFSERR_NOTEMPTY,    ENOTEMPTY    },
  457.     { NFSERR_DQUOT,        EDQUOT        },
  458.     { NFSERR_STALE,        ESTALE        },
  459. #ifdef EWFLUSH
  460.     { NFSERR_WFLUSH,    EWFLUSH        },
  461. #endif
  462.     { -1,            EIO        }
  463. };
  464.  
  465. static char *nfs_strerror(int stat)
  466. {
  467.     int i;
  468.     static char buf[256];
  469.  
  470.     for (i = 0; nfs_errtbl[i].stat != -1; i++) {
  471.         if (nfs_errtbl[i].stat == stat)
  472.             return strerror(nfs_errtbl[i].errno);
  473.     }
  474.     sprintf(buf, "unknown nfs status return value: %d", stat);
  475.     return buf;
  476. }
  477.  
  478.